/**
 * @fileOverview 事件
 * @author <a href="mailto:lexloo@126.com">lexloo</a>
 */

(function() {
	if (typeof $XEvent != 'undefined') {
		return;
	}

	/**
	 * @static
	 * @class 事件类
	 * @author <a href="mailto:lexloo@126.com">lexloo</a>
	 */
	com.firefly.XEvent = {
		/**
		 * 文档准备好后执行的功能列表
		 */
		readyList : [],
		/**
		 * 文档是否准备好
		 */
		contentReady : false,
		/**
		 * 空格键
		 * 
		 * @constant
		 * @type Number
		 */
		BACKSPACE : 8,
		/**
		 * Tab键
		 * 
		 * @constant
		 * @type Number
		 */
		TAB : 9,
		/**
		 * 回车键
		 * 
		 * @constant
		 * @type Number
		 */
		ENTER : 13,
		/**
		 * ESC键
		 * 
		 * @constant
		 * @type Number
		 */
		ESC : 27,
		/**
		 * 左键
		 * 
		 * @constant
		 * @type Number
		 */
		LEFT : 37,
		/**
		 * 上键
		 * 
		 * @constant
		 * @type Number
		 */
		UP : 38,
		/**
		 * 右键
		 * 
		 * @constant
		 * @type Number
		 */
		RIGHT : 39,
		/**
		 * 下键
		 * 
		 * @constant
		 * @type Number
		 */
		DOWN : 40,
		/**
		 * 删除键
		 * 
		 * @constant
		 * @type Number
		 */
		DELETE : 46,

		/**
		 * 添加监听器
		 * 
		 * @param {HTMLElement/String}
		 *            element 需要添加监听的HTML元素对象
		 * @param {String}
		 *            evtName 事件名称
		 * @param {Function}
		 *            fn 监听函数
		 */
		addListener : function() {
			var updateLstnList = function(element, evtName, fn) {
				/* 监听器列表 */
				if (element.lstnList == null) {
					element.lstnList = [];
				}

				var entry = {
					'name' : evtName,
					'fn' : fn
				};

				element.lstnList.push(entry);
			};

			if ($Env.isDOMCompatiable) {
				return function(element, evtName, fn) {
					element = $(element);

					/* 用于冒泡过程 */
					element.addEventListener(evtName, fn, false);
					updateLstnList(element, evtName, fn);
				};
			} else {
				return function(element, evtName, fn) {
					element = $(element);

					element.attachEvent('on' + evtName, fn);
					updateLstnList(element, evtName, fn);
				};
			}
		}(),

		/**
		 * 移除监听器
		 * 
		 * @param {HTMLElement/String}
		 *            element 需要添加监听的HTML元素对象
		 * @param {String}
		 *            evtName 事件名称
		 * @param {Function}
		 *            fn 监听函数
		 */
		removeListener : function() {
			var updateLstnList = function(element, evtName, fn) {
				if (element.lstnList != null) {
					var count = element.lstnList.length;
					for ( var i = 0; i < count; i++) {
						var o = element.lstnList[i];
						if (o.fn == fn) {
							element.lstnList.splice(i, 1);
							break;
						}
					}

					if (element.lstnList.length == 0) {
						element.lstnList = null;
					}
				}
			};
			if ($Env.isDOMCompatiable) {
				return function(element, eventName, fn) {
					element = $(element);

					/* 用于冒泡过程 */
					element.removeEventListener(evtName, fn, false);
					updateLstnList(element, evtName, fn);
				};
			} else {
				return function(element, evtName, fn) {
					element = $(element);

					element.detachEvent('on' + evtName, fn);
					updateLstnList(element, evtName, fn);
				};
			}
		}(),

		/**
		 * 移除元素所有事件监听器
		 * 
		 * @param {HTMLElement/String}
		 *            element 需要移除监听器的元素
		 */
		removeAllListeners : function(element) {
			var list = $(element).lstnList;
			if (list) {
				while (list.length > 0) {
					var entry = list[0];
					$XEvent.removeListener(element, entry.name, entry.fn);
				}
			}
		},

		/**
		 * 释放节点及其所有子节点的事件监听
		 * 
		 * @param {HTMLElement/String}
		 *            element 节点元素
		 */
		release : function(element) {
			if (element) {
				this.removeAllListeners(element);
				$A(element.childNodes).each(function(c) {
					$XEvent.release(c);
				});
			}
		},

		/**
		 * 使右键菜单无效
		 * 
		 * @param {HTMLElement/String}
		 *            element 节点元素
		 */
		disableContextMenu : function() {
			if ($Env.isDOMCompatiable) {
				return function(element) {
					$(element).setAttribute('oncontextmenu', 'return false;');
				};
			} else {
				return function(element) {
					$XEvent.addListener(element, 'contextmenu', function() {
						return false;
					});
				};
			}
		}(),

		/**
		 * 获取事件源
		 * 
		 * @param {EventObject}
		 *            evt 事件
		 * @returns {Object} 事件源
		 */
		getSource : function(evt) {
			return (evt.srcElement != null) ? evt.srcElement : evt.target;
		},

		/**
		 * 事件是否已经消费
		 * 
		 * @param {EventObject}
		 *            evt 事件
		 * @returns {Boolean} 事件是否已经消费
		 */
		isConsumed : function(evt) {
			return evt.isConsumed != null && evt.isConsumed;
		},

		/**
		 * 是否左键按下
		 * 
		 * @returns {Boolean}
		 * 
		 */
		isLeftMouseButton : function(evt) {
			return evt.button == ($Env.isDOMCompatiable ? 0 : 1);
		},

		/**
		 * 是否右键按下
		 * 
		 * @returns {Boolean}
		 */
		isRightMouseButton : function(evt) {
			return evt.button == 2;
		},

		/**
		 * 是否显示弹出菜单
		 * 
		 * @param {EventObject}
		 *            evt 事件
		 * @returns {Boolean}
		 */
		isPopupTrigger : function(evt) {
			return $XEvent.isRightMouseButton(evt) || ($XEvent.isShiftDown(evt) && !$XEvent.isControlDown(evt));
		},

		/**
		 * 是否按下shift
		 * 
		 * @returns {Boolean}
		 */
		isShiftDown : function(evt) {
			return (evt != null) ? evt.shiftKey : false;
		},

		/**
		 * 是否按下alt
		 * 
		 * @returns {Boolean}
		 */
		isAltDown : function(evt) {
			return (evt != null) ? evt.altKey : false;
		},

		/**
		 * 是否按下control
		 * 
		 * @returns {Boolean}
		 */
		isControlDown : function(evt) {
			return (evt != null) ? evt.ctrlKey : false;
		},

		/**
		 * 是否按下meta
		 * 
		 * @returns {Boolean}
		 */
		isMetaDown : function(evt) {
			return (evt != null) ? evt.metaKey : false;
		},

		/**
		 * 获得事件发生时页面鼠标x坐标.
		 * 
		 * @param {DOMEvent}
		 *            evt
		 * @return {Number} pageX
		 */
		pageX : function(evt) {
			if (evt.pageX == null && evt.clientX != null) {
				var doc = document.documentElement, body = document.body;
				var diff = (doc && doc.scrollLeft || body && body.scrollLeft || 0);
				return evt.clientX + diff - (doc.clientLeft || 0);
			}
			return evt.pageX;
		},

		/**
		 * 获得事件发生时页面鼠标y坐标.
		 * 
		 * @param {DOMEvent}
		 *            evt
		 * @return {Number} pageY
		 */
		pageY : function(evt) {
			if (evt.pageY == null && evt.clientY != null) {
				var doc = document.documentElement, body = document.body;
				var diff = (doc && doc.scrollTop || body && body.scrollTop || 0);
				return evt.clientY + diff - (doc.clientTop || 0);
			}
			return evt.pageY;
		},

		/**
		 * 获得事件发生时页面鼠标xy坐标.
		 * 
		 * @param {DOMEvent}
		 *            evt
		 * @return {Array} [pageY,pageY]
		 */
		pageXY : function(evt) {
			if (evt.pageX == null && evt.clientX != null) {
				var doc = document.documentElement, body = document.body;
				var diffX = (doc && doc.scrollLeft || body && body.scrollLeft || 0);
				var diffY = (doc && doc.scrollTop || body && body.scrollTop || 0);
				return [ evt.clientX + diffX - (doc.clientLeft || 0), evt.clientY + diffY - (doc.clientTop || 0) ];
			}
			return [ evt.pageX, evt.pageY ];
		},

		/**
		 * 消费事件，使其不产生后续动作
		 * 
		 * @param {EventObject}
		 *            evt 事件
		 * @param {Boolean}
		 *            preventDefault 是否取消冒泡
		 */
		consume : function(evt, preventDefault) {
			if (preventDefault == null || preventDefault) {
				if (evt.preventDefault) {
					evt.stopPropagation();
					evt.preventDefault();
				} else {
					evt.cancelBubble = true;
				}
			}
			evt.isConsumed = true;
			evt.returnValue = false;
		},

		/**
		 * @private 页面加载完成后回调
		 */
		ready : function(callback) {
			this.readyList.push(callback);
		},

		/**
		 * @private
		 */
		onContentLoad : function() {
			if (!$XEvent.contentReady) {
				$XEvent.contentReady = true;

				$A($XEvent.readyList).each(function(fn){
					fn.call(window);
				});
			}
		}
	};

	/**
	 * com.firefly.XEvent的快捷访问
	 */
	$XEvent = com.firefly.XEvent;

	/**
	 * 添加DOM加载完成后回调函数
	 */
	$Ready = function() {
		$A(arguments).each(function(callback) {
			$XEvent.ready.apply($XEvent, arguments);
		});
	};

	if ($Env.isIE) {
		(function() {
			if ($XEvent.contentReady)
				return;
			try {
				// If IE is used, use the trick by Diego Perini
				// http://javascript.nwbox.com/IEContentLoaded/
				document.documentElement.doScroll("left");
			} catch (error) {
				setTimeout(arguments.callee, 0);
				return;
			}

			// and execute any waiting functions
			$XEvent.onContentLoad();
		})();
	}

	$XEvent.addListener(window, "load", $XEvent.onContentLoad);
})();